home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / doom / quake2.zip / TF1_2SRC.ZIP / QUAKE / FORTRESS / SOURCE / TFORTMAP.QC < prev    next >
Text File  |  1996-09-10  |  30KB  |  1,256 lines

  1. /* 
  2.     TeamFortress 1.2    -    7/9/96
  3.  
  4.     Robin Walker, John Cook, Ian Caughley.
  5.  
  6.     Functions handling TeamFortress Map Goal Entities
  7. */
  8. // Prototypes
  9. // Team Functions
  10. void(float tno, float scoretoadd) TeamFortress_TeamIncreaseScore;
  11. void(float all) TeamFortress_TeamShowScores;
  12. float() TeamFortress_TeamGetWinner;
  13.  
  14. // AutoDetect entity
  15. void() info_tfdetect;
  16.  
  17. // Functions to handle spawning
  18. void() TF_PlaceItem;
  19. void() TF_StartItem;
  20.  
  21. // TeamSpawnpoint Functions
  22. void() info_player_teamspawn;
  23.  
  24. // Goal Functions
  25. void() info_tfgoal;
  26. void() tfgoal_touch;
  27. void() tfgoal_activate;
  28. void(entity Goal, entity AP, float addb) tfgoal_result;
  29. void(entity Goal, entity AP, float addb) tfgoal_normal_result;
  30. void(entity Goal, entity AP, float addb) tfgoal_timer_result;
  31. void() tfgoal_respawn;
  32. void() tfgoal_timer_tick;
  33. void(entity Goal, entity AP) tfgoal_goal_group;
  34. void() TeamFortress_CheckClassStats;
  35. entity(float gno) tfgoal_findgoal;
  36.  
  37. // GoalItem Functions
  38. void() item_tfgoal;
  39. void() item_tfgoal_touch;
  40. void(entity Item) tfgoalitem_drop;
  41. void() tfgoalitem_remove;
  42. void() tfgoalitem_checkgoalreturn;
  43. void(entity Item, entity AP) tfgoalitem_GiveToAP;
  44. void(entity Item, entity AP, float method) tfgoalitem_RemoveFromAP;
  45. entity(float ino) tfgoal_finditem;
  46.  
  47. //=========================================================================
  48. // AUTODETECT ENTITY FUNCTIONS
  49. //=========================================================================
  50. //=========================================================================
  51. // Spawn the detection entity
  52. void() info_tfdetect =
  53. {
  54.     self.solid = SOLID_NOT;
  55.     setsize (self, '-16 -16 -24', '16 16 32');
  56. };
  57.  
  58. //=========================================================================
  59. // SPAWNING FUNCTIONS
  60. //=========================================================================
  61. //=========================================================================
  62. // Place the Goal Item
  63. void() TF_PlaceItem =
  64. {
  65.     local float    oldz;
  66.  
  67.     self.flags = FL_ITEM;                // make extra wide
  68.     self.movetype = MOVETYPE_TOSS;    
  69.     self.velocity = '0 0 0';
  70.     self.oldorigin = self.origin;         // So we can return it later
  71. };
  72.  
  73. //=========================================================================
  74. // Start the Goal Item
  75. void() TF_StartItem =
  76. {
  77.     self.nextthink = time + 0.2;    // items start after other solids
  78.     self.think = TF_PlaceItem;
  79. };
  80.  
  81. //=========================================================================
  82. // Place the Goal 
  83. void() TF_PlaceGoal =
  84. {
  85.     local float    oldz;
  86.  
  87.     if (!(self.goal_activation & TFGA_TIMER_GOAL))
  88.     {
  89.         self.touch = tfgoal_touch;
  90.     }
  91.     else
  92.     {
  93.         if (self.search_time <= 0)
  94.         {
  95.             dprint("Timer Goal with no search_time specified.\n");
  96.             remove(self);
  97.         }
  98.         // Set up the next Timer Tick
  99.         self.think = tfgoal_timer_tick;
  100.         self.nextthink = time + self.search_time;
  101.     }
  102.  
  103.     self.flags = FL_ITEM;                // make extra wide
  104.     self.movetype = MOVETYPE_NONE;    
  105.     self.velocity = '0 0 0';
  106.     self.oldorigin = self.origin;         // So we can return it later
  107. };
  108.  
  109. //=========================================================================
  110. // Start the Goal 
  111. void() TF_StartGoal =
  112. {
  113.     self.nextthink = time + 0.2;    // items start after other solids
  114.     self.think = TF_PlaceGoal;
  115. };
  116.  
  117. //=========================================================================
  118. // Spawnpoints for team games with FortressMap
  119. void() info_player_teamspawn =
  120. {
  121.     if ((self.spawnflags) && (self.team_no == 0))
  122.         self.team_no = self.spawnflags;
  123.  
  124.     // find the highest team number
  125.     if (number_of_teams < self.team_no)
  126.         number_of_teams = self.team_no;
  127.  
  128.     // Team spawnpoints must have a team associated with them
  129.     if (self.team_no <= 0)
  130.     {
  131.         dprint("no team_no associated with info_player_teamspawn\n");
  132.         remove(self);
  133.     }
  134. };
  135.  
  136. //=========================================================================
  137. // GOAL FUNCTIONS
  138. //=========================================================================
  139. //=========================================================================
  140. // Spawn the goal entity
  141. void() info_tfgoal =
  142. {
  143.     self.solid = SOLID_TRIGGER;
  144.     self.goal_state = TFGS_INACTIVE;
  145.     setsize (self, '-16 -16 -24', '16 16 32');
  146.     TF_StartGoal ();
  147. };
  148.  
  149. //=========================================================================
  150. // Touch function for the goal entity
  151. void() tfgoal_touch =
  152. {
  153.     local string    st;
  154.  
  155.     if (other.classname != "player")
  156.         return;
  157.  
  158.     // Fortressmap is off?
  159.     if (!(toggleflags & TFLAG_FORTRESSMAP))
  160.         return;
  161.  
  162.     // If it's a Timer Goal, return
  163.     if (self.goal_activation & TFGA_TIMER_GOAL)
  164.         return;
  165.  
  166.     // If it is not activated in by the player's touch, return
  167.     if (!(self.goal_activation & TFGA_TOUCH))
  168.         return;
  169.  
  170.     // Attempt to activate it
  171.     tfgoal_activate();
  172. };
  173.  
  174. //=========================================================================
  175. // Last check before activation. self = goal, other = player who activated it
  176. void() tfgoal_activate =
  177. {
  178.     local entity te;
  179.     local string db;
  180.  
  181.     // If a player of a specific team can only activate this
  182.     if (self.goal_activation & TFGA_TEAM)
  183.     {
  184.         if (self.team_no != other.team_no)
  185.             return;
  186.     }
  187.  
  188.     // If a player of a specific class can only activate this
  189.     if (self.goal_activation & TFGA_CLASS)
  190.     {
  191.         if (self.playerclass != other.playerclass)
  192.             return;
  193.     }
  194.  
  195.     // If this activation needs a GoalItem, make sure the player has it
  196.     if (self.goal_activation & TFGA_ITEM)
  197.     {
  198.         te = tfgoal_finditem(self.items_allowed);
  199.         if (te.owner != other)
  200.             return;
  201.     }
  202.  
  203.  
  204.     // It's all ok.
  205.     // Do the results, adding the bonuses
  206.     tfgoal_result(self, other, 1);
  207. };
  208.  
  209. //=========================================================================
  210. // Goal has been activated. 
  211. // addb : >0 if you want to add bonuses of the goal to the AP
  212. void(entity Goal, entity AP, float addb) tfgoal_result =
  213. {
  214.     // If it's a Timer Goal, call the Timer Goal activation
  215.     if (Goal.goal_activation & TFGA_TIMER_GOAL)
  216.     {
  217.         tfgoal_timer_result(Goal, AP, addb);
  218.         return;
  219.     }
  220.  
  221.     // Otherwise, call the Normal Goal activation
  222.     tfgoal_normal_result(Goal, AP, addb);
  223. };
  224.  
  225. //=========================================================================
  226. // Normal Goal has been activated. 
  227. // addb : >0 if you want to add bonuses of the goal to the AP
  228. void(entity Goal, entity AP, float addb) tfgoal_normal_result =
  229. {
  230.     local entity te, oldself;
  231.     local string st;
  232.     local float winners;
  233.  
  234.     // Is the goal already activated?
  235.     // This check is needed for goals which are being activated by other goals
  236.     if (Goal.goal_state == TFGS_ACTIVE)
  237.         return;
  238.  
  239.     // Goal is now active
  240.     Goal.goal_state = TFGS_ACTIVE;
  241.     stuffcmd (AP, "bf\n");
  242.  
  243.     // Display the message and increase the team score
  244.     if (Goal.netname)
  245.         bprint(Goal.netname);
  246.     if (Goal.message)
  247.         sprint(AP, Goal.message);
  248.     if (Goal.count > 0)
  249.     {
  250.         if (AP.team_no > 0)
  251.         {
  252.             TeamFortress_TeamIncreaseScore(AP.team_no, Goal.count);
  253.             // Display short team scores
  254.             TeamFortress_TeamShowScores(2);
  255.         }
  256.     }
  257.  
  258.     // Apply Stats, only if told to
  259.     if (addb)
  260.     {
  261.         if (Goal.health > 0)
  262.             T_Heal(AP, Goal.health, 0);
  263.         if (Goal.health < 0)
  264.             T_Damage(AP, Goal, Goal, (0 - Goal.health));
  265.         AP.armortype = AP.armortype + Goal.armortype;
  266.         AP.armorvalue = AP.armorvalue + Goal.armorvalue;
  267.         AP.frags = AP.frags + Goal.frags;
  268.         AP.ammo_shells = AP.ammo_shells + Goal.ammo_shells;
  269.         AP.ammo_nails = AP.ammo_nails + Goal.ammo_nails;
  270.         AP.ammo_rockets = AP.ammo_rockets + Goal.ammo_rockets;
  271.         AP.ammo_cells = AP.ammo_cells + Goal.ammo_cells;
  272.         AP.ammo_medikit = AP.ammo_medikit + Goal.ammo_medikit;
  273.         AP.ammo_detpack = AP.ammo_detpack + Goal.ammo_detpack;
  274.         AP.no_grenades_1 = AP.no_grenades_1 + Goal.no_grenades_1;
  275.         AP.no_grenades_2 = AP.no_grenades_2 + Goal.no_grenades_2;
  276.     
  277.         // Apply any powerups
  278.         if (Goal.invincible_finished > 0)
  279.         {
  280.             AP.items = AP.items | IT_INVULNERABILITY;
  281.              AP.invincible_time = 1;
  282.             AP.invincible_finished = time + Goal.invincible_finished;
  283.         }
  284.         if (Goal.invisible_finished > 0)
  285.         {
  286.             AP.items = AP.items | IT_INVISIBILITY;
  287.              AP.invisible_time = 1;
  288.             AP.invisible_finished = time + Goal.invisible_finished;
  289.         }
  290.         if (Goal.super_damage_finished > 0)
  291.         {
  292.             AP.items = AP.items | IT_QUAD;
  293.              AP.super_time = 1;
  294.             AP.super_damage_finished = time + Goal.super_damage_finished;
  295.         }
  296.         if (Goal.radsuit_finished > 0)
  297.         {
  298.             AP.items = AP.items | IT_SUIT;
  299.              AP.rad_time = 1;
  300.             AP.radsuit_finished = time + Goal.radsuit_finished;
  301.         }
  302.  
  303.         // Now apply the Playerclass limitations & Redisplay Ammo counts
  304.         oldself = self;
  305.         self = AP;
  306.         TeamFortress_CheckClassStats();
  307.         W_SetCurrentAmmo ();
  308.         self = oldself;
  309.     }
  310.  
  311.     // If there's a GoalItem for this goal, give it to the player
  312.     if (Goal.goal_result & TFGR_ITEM)
  313.     {
  314.         if (Goal.items != 0)
  315.         {
  316.             // Find the item
  317.             te = tfgoal_finditem(Goal.items);
  318.             if (te)
  319.             {
  320.                 // Give it to the player
  321.                 tfgoalitem_GiveToAP(te, AP);
  322.             }
  323.         }
  324.         else
  325.         {
  326.             // No item specified in .items. Print error.
  327.             bprint("Goal ");
  328.             st = ftos(Goal.goal_no);
  329.             bprint(st);
  330.             bprint(" has goal_result bit ");
  331.             st = ftos(TFGR_ITEM);
  332.             bprint(st);
  333.             bprint(" set, but no .items specified.\n");
  334.         }
  335.     }
  336.  
  337.     // If this goal removes an item from the player, remove it
  338.     if (Goal.goal_result & TFGR_ITEM_REMOVE)
  339.     {
  340.         if (Goal.axhitme != 0)
  341.         {
  342.             te = find (world, classname, "item_tfgoal");
  343.             while (te)
  344.             {
  345.                 if ((te.owner == AP) && (te.goal_no == Goal.axhitme))
  346.                 {
  347.                     // Remove it from the player
  348.                     tfgoalitem_RemoveFromAP(te, AP, 1);
  349.                 }
  350.                 te = find(te, classname, "item_tfgoal");
  351.             }
  352.         }
  353.         else
  354.         {
  355.             // No item specified in .items. Print error.
  356.             bprint("Goal ");
  357.             st = ftos(Goal.goal_no);
  358.             bprint(st);
  359.             bprint(" has goal_result bit ");
  360.             st = ftos(TFGR_ITEM_REMOVE);
  361.             bprint(st);
  362.             bprint(" set, but no .axhitme specified.\n");
  363.         }
  364.     }
  365.  
  366.     // Does this goal end the level?
  367.     if (Goal.goal_result & TFGR_ENDGAME)
  368.     {
  369.         // Display Long TeamScores to everyone
  370.         TeamFortress_TeamShowScores(1);
  371.         winners = TeamFortress_TeamGetWinner();
  372.  
  373.         // Stop everyone
  374.         te = find (world, classname, "player");
  375.         while (te)
  376.         {
  377.             te.takedamage = 0;
  378.             te.movetype = MOVETYPE_NONE;
  379.  
  380.             // Can't append strings for centerprint :(
  381.             if (winners == 1)
  382.                 centerprint(te, "Team 1 wins!\n");
  383.             if (winners == 2)
  384.                 centerprint(te, "Team 2 wins!\n");
  385.             if (winners == 3)
  386.                 centerprint(te, "Team 3 wins!\n");
  387.             if (winners == 4)
  388.                 centerprint(te, "Team 4 wins!\n");
  389.  
  390.             te = find(te, classname, "player");
  391.         }
  392.  
  393.         te = spawn();
  394.         te.nextthink = time + 5; // Allow 3 secs to read the scores
  395.         te.think = execute_changelevel;
  396.  
  397.         remove(Goal);
  398.         return;
  399.     }
  400.  
  401.     // Do Goal Group checking
  402.     tfgoal_goal_group(Goal, AP);
  403.  
  404.     // If another goal should be activated, activate it
  405.     if (Goal.goal_result & TFGR_GOAL_ACTIVATE)
  406.     {
  407.         if (Goal.impulse != 0)
  408.         {
  409.             // Find the goal
  410.             te = tfgoal_findgoal(Goal.impulse);
  411.             if (te)
  412.             {
  413.                 tfgoal_result(te, AP, (!(AP.goal_result & TFGR_NO_ACT_BONUS)));
  414.             }
  415.         }
  416.         else
  417.         {
  418.             // No goal specified in .impulse. Print error.
  419.             bprint("Goal ");
  420.             st = ftos(Goal.goal_no);
  421.             bprint(st);
  422.             bprint(" has goal_result bit ");
  423.             st = ftos(TFGR_GOAL_ACTIVATE);
  424.             bprint(st);
  425.             bprint(" set, but no .impulse specified.\n");
  426.         }
  427.     }
  428.  
  429.     // If another goal should be removed, remove it
  430.     if (Goal.goal_result & TFGR_GOAL_REMOVE)
  431.     {
  432.         if (Goal.waitmin != 0)
  433.         {
  434.             // Find the goal
  435.             te = tfgoal_findgoal(Goal.waitmin);
  436.             if (te)
  437.             {
  438.                 te.solid = SOLID_NOT;
  439.                 te.goal_state = TFGS_REMOVED;
  440.             }
  441.         }
  442.         else
  443.         {
  444.             // No goal specified in .waitmin. Print error.
  445.             bprint("Goal ");
  446.             st = ftos(Goal.goal_no);
  447.             bprint(st);
  448.             bprint(" has goal_result bit ");
  449.             st = ftos(TFGR_GOAL_REMOVE);
  450.             bprint(st);
  451.             bprint(" set, but no .waitmin specified.\n");
  452.         }
  453.     }
  454.  
  455.     // If another goal should be restored, restore it
  456.     if (Goal.goal_result & TFGR_GOAL_RESTORE)
  457.     {
  458.         if (Goal.waitmax != 0)
  459.         {
  460.             // Find the goal
  461.             te = tfgoal_findgoal(Goal.waitmax);
  462.             if (te)
  463.             {
  464.                 if (te.goal_state == TFGS_REMOVED)
  465.                 {
  466.                     te.solid = SOLID_TRIGGER;
  467.                     te.goal_state = TFGS_INACTIVE;
  468.                 }
  469.             }
  470.         }
  471.         else
  472.         {
  473.             // No goal specified in .waitmax. Print error.
  474.             bprint("Goal ");
  475.             st = ftos(Goal.goal_no);
  476.             bprint(st);
  477.             bprint(" has goal_result bit ");
  478.             st = ftos(TFGR_GOAL_RESTORE);
  479.             bprint(st);
  480.             bprint(" set, but no .waitmax specified.\n");
  481.         }
  482.     }
  483.  
  484.     // If another goal should be inactivated, inactivate it
  485.     if (Goal.goal_result & TFGR_GOAL_INACTIVATE)
  486.     {
  487.         if (Goal.distance != 0)
  488.         {
  489.             // Find the goal
  490.             te = tfgoal_findgoal(Goal.distance);
  491.             if (te)
  492.             {
  493.                 if (te.goal_state == TFGS_ACTIVE)
  494.                 {
  495.                     te.solid = SOLID_TRIGGER;
  496.                     te.goal_state = TFGS_INACTIVE;
  497.                 }
  498.             }
  499.         }
  500.         else
  501.         {
  502.             // No goal specified in .waitmax. Print error.
  503.             bprint("Goal ");
  504.             st = ftos(Goal.goal_no);
  505.             bprint(st);
  506.             bprint(" has goal_result bit ");
  507.             st = ftos(TFGR_GOAL_INACTIVATE);
  508.             bprint(st);
  509.             bprint(" set, but no .distance specified.\n");
  510.         }
  511.     }
  512.  
  513.     // Check status of respawn for this goal
  514.     // Single Activation, do nothing
  515.     if (Goal.goal_result & TFGR_SINGLE)
  516.     {
  517.         Goal.solid = SOLID_NOT;
  518.         return;
  519.     }
  520.     // Respawn Activation, set up respawn
  521.     if (Goal.goal_result & TFGR_RESPAWN)
  522.     {
  523.         Goal.solid = SOLID_NOT;
  524.           Goal.nextthink = time + Goal.wait;
  525.         Goal.think = tfgoal_respawn;
  526.         return;
  527.     }
  528.     // Otherwise, it's a Multiple Goal
  529.     Goal.goal_state = TFGS_INACTIVE;
  530. };
  531.  
  532. //=========================================================================
  533. // Timer Goal has been activated. 
  534. // addb : >0 if you want to add bonuses of the goal to the AP
  535. // AP and addb are still passed in, since I'll add in the ability to
  536. // use an AP shortly.
  537. void(entity Goal, entity AP, float addb) tfgoal_timer_result =
  538. {
  539.     local entity te, oldself;
  540.     local string st;
  541.     local float winners;
  542.  
  543.     // Is the goal already activated?
  544.     // This check is needed for goals which are being activated by other goals
  545.     if (Goal.goal_state == TFGS_ACTIVE)
  546.         return;
  547.  
  548.     // Goal is now active
  549.     Goal.goal_state = TFGS_ACTIVE;
  550.  
  551.     // Display the message and increase the team score
  552.     if (Goal.netname)
  553.         bprint(Goal.netname);
  554.  
  555.     // Does this goal end the level?
  556.     if (Goal.goal_result & TFGR_ENDGAME)
  557.     {
  558.         // Display Long TeamScores to everyone
  559.         TeamFortress_TeamShowScores(1);
  560.         winners = TeamFortress_TeamGetWinner();
  561.  
  562.         // Stop everyone
  563.         te = find (world, classname, "player");
  564.         while (te)
  565.         {
  566.             te.takedamage = 0;
  567.             te.movetype = MOVETYPE_NONE;
  568.  
  569.             // Can't append strings for centerprint :(
  570.             if (winners == 1)
  571.                 centerprint(te, "Team 1 wins!\n");
  572.             if (winners == 2)
  573.                 centerprint(te, "Team 2 wins!\n");
  574.             if (winners == 3)
  575.                 centerprint(te, "Team 3 wins!\n");
  576.             if (winners == 4)
  577.                 centerprint(te, "Team 4 wins!\n");
  578.  
  579.             te = find(te, classname, "player");
  580.         }
  581.  
  582.         te = spawn();
  583.         te.nextthink = time + 5; // Allow 3 secs to read the scores
  584.         te.think = execute_changelevel;
  585.  
  586.         remove(Goal);
  587.         return;
  588.     }
  589.  
  590.     // Do Goal Group checking
  591.     // No activations!
  592.     if (!(Goal.goal_group & TFGG_ACTIVATE))
  593.         tfgoal_goal_group(Goal, AP);
  594.     else
  595.         bprint("Timer Goal attempting to do Goal Group actions!\n");
  596.  
  597.     // If another goal should be removed, remove it
  598.     if (Goal.goal_result & TFGR_GOAL_REMOVE)
  599.     {
  600.         if (Goal.waitmin != 0)
  601.         {
  602.             // Find the goal
  603.             te = tfgoal_findgoal(Goal.waitmin);
  604.             if (te)
  605.             {
  606.                 te.solid = SOLID_NOT;
  607.                 te.goal_state = TFGS_REMOVED;
  608.             }
  609.         }
  610.         else
  611.         {
  612.             // No goal specified in .waitmin. Print error.
  613.             bprint("Goal ");
  614.             st = ftos(Goal.goal_no);
  615.             bprint(st);
  616.             bprint(" has goal_result bit ");
  617.             st = ftos(TFGR_GOAL_REMOVE);
  618.             bprint(st);
  619.             bprint(" set, but no .waitmin specified.\n");
  620.         }
  621.     }
  622.  
  623.     // If another goal should be restored, restore it
  624.     if (Goal.goal_result & TFGR_GOAL_RESTORE)
  625.     {
  626.         if (Goal.waitmax != 0)
  627.         {
  628.             // Find the goal
  629.             te = tfgoal_findgoal(Goal.waitmax);
  630.             if (te)
  631.             {
  632.                 if (te.goal_state == TFGS_REMOVED)
  633.                 {
  634.                     te.solid = SOLID_TRIGGER;
  635.                     te.goal_state = TFGS_INACTIVE;
  636.                 }
  637.             }
  638.         }
  639.         else
  640.         {
  641.             // No goal specified in .waitmax. Print error.
  642.             bprint("Goal ");
  643.             st = ftos(Goal.goal_no);
  644.             bprint(st);
  645.             bprint(" has goal_result bit ");
  646.             st = ftos(TFGR_GOAL_RESTORE);
  647.             bprint(st);
  648.             bprint(" set, but no .waitmax specified.\n");
  649.         }
  650.     }
  651.  
  652.     // If another goal should be inactivated, inactivate it
  653.     if (Goal.goal_result & TFGR_GOAL_INACTIVATE)
  654.     {
  655.         if (Goal.distance != 0)
  656.         {
  657.             // Find the goal
  658.             te = tfgoal_findgoal(Goal.distance);
  659.             if (te)
  660.             {
  661.                 if (te.goal_state == TFGS_ACTIVE)
  662.                 {
  663.                     te.solid = SOLID_TRIGGER;
  664.                     te.goal_state = TFGS_INACTIVE;
  665.                 }
  666.             }
  667.         }
  668.         else
  669.         {
  670.             // No goal specified in .waitmax. Print error.
  671.             bprint("Goal ");
  672.             st = ftos(Goal.goal_no);
  673.             bprint(st);
  674.             bprint(" has goal_result bit ");
  675.             st = ftos(TFGR_GOAL_INACTIVATE);
  676.             bprint(st);
  677.             bprint(" set, but no .distance specified.\n");
  678.         }
  679.     }
  680.  
  681.     // Set up the next Timer Tick
  682.     Goal.goal_state = TFGS_INACTIVE;
  683.     Goal.think = tfgoal_timer_tick;
  684.     Goal.nextthink = time + Goal.search_time;
  685. };
  686.  
  687. //=========================================================================
  688. // Respawn the goal
  689. void() tfgoal_respawn =
  690. {
  691.     if (self.goal_state != TFGS_REMOVED)
  692.     {
  693.         self.goal_state = TFGS_INACTIVE;
  694.         self.solid = SOLID_TRIGGER;    // allow it to be touched again
  695.     }
  696. };
  697.  
  698. //=========================================================================
  699. // Activate the Timer goal
  700. void() tfgoal_timer_tick =
  701. {
  702.     if (self.goal_state != TFGS_REMOVED)
  703.     {
  704.         tfgoal_result(self, world, 0);    // Do Timer Tick again
  705.     }
  706. };
  707.  
  708. //=========================================================================
  709. // Check and do any behaviour for the goal's group
  710. void(entity Goal, entity AP) tfgoal_goal_group =
  711. {
  712.     local string st;
  713.     local entity tg;
  714.     local float allset;
  715.  
  716.     // Check all goals activated flag
  717.     if (Goal.goal_group & TFGG_ACTIVATE)
  718.     {
  719.         // Make sure a valid group no is specified
  720.         if (Goal.height == 0)
  721.         {
  722.             // No goal specified in .height. Print error.
  723.             bprint("Goal ");
  724.             st = ftos(Goal.goal_no);
  725.             bprint(st);
  726.             bprint(" has goal_group bit ");
  727.             st = ftos(TFGG_ACTIVATE);
  728.             bprint(st);
  729.             bprint(" set, but no .height specified.\n");
  730.         }
  731.         else if (Goal.last_impulse == 0)
  732.         {
  733.             // No goal specified in .lastimpulse. Print error.
  734.             bprint("Goal ");
  735.             st = ftos(Goal.goal_no);
  736.             bprint(st);
  737.             bprint(" has goal_group bit ");
  738.             st = ftos(TFGG_ACTIVATE);
  739.             bprint(st);
  740.             bprint(" set, but no .last_impulse specified.\n");
  741.         }
  742.         else
  743.         {
  744.             allset = 1;
  745.             // Find all goals
  746.             tg = find (world, classname, "info_tfgoal");
  747.             while (tg)
  748.             {
  749.                 if (tg.group_no == Goal.height)
  750.                 {
  751.                     if (tg.goal_state != TFGS_ACTIVE)
  752.                         allset = 0;
  753.                 }
  754.         
  755.                 tg = find(tg, classname, "info_tfgoal");
  756.             }
  757.             
  758.             // If all goals in this group are activated, do it
  759.             if (allset)
  760.             {
  761.                 // Find the goal
  762.                 tg = tfgoal_findgoal(Goal.last_impulse);
  763.                 if (tg)
  764.                 {
  765.                     tfgoal_result(tg, AP, 0);    // Don't apply bonuses
  766.                 }
  767.             }
  768.         }
  769.     }
  770.  
  771.     // Check Activate all in the group flag
  772.     if (Goal.goal_group & TFGG_ACTIVATE_ALL)
  773.     {
  774.         // Make sure a valid group no is specified
  775.         if (Goal.aflag == 0)
  776.         {
  777.             // No goal specified in .aflag. Print error.
  778.             bprint("Goal ");
  779.             st = ftos(Goal.goal_no);
  780.             bprint(st);
  781.             bprint(" has goal_group bit ");
  782.             st = ftos(TFGG_ACTIVATE_ALL);
  783.             bprint(st);
  784.             bprint(" set, but no .aflag specified.\n");
  785.         }
  786.         else
  787.         {
  788.             // Find all goals
  789.             tg = find (world, classname, "info_tfgoal");
  790.             while (tg)
  791.             {
  792.                 if (tg.group_no == Goal.aflag)
  793.                 {
  794.                     tfgoal_result(tg, AP, 0);    // Don't apply bonuses
  795.                 }
  796.         
  797.                 tg = find(tg, classname, "info_tfgoal");
  798.             }
  799.         }
  800.     }
  801.  
  802.     // Check Inactivate all in the group flag
  803.     if (Goal.goal_group & TFGG_INACTIVATE_ALL)
  804.     {
  805.         // Make sure a valid group no is specified
  806.         if (Goal.dmg == 0)
  807.         {
  808.             // No goal specified in .dmg. Print error.
  809.             bprint("Goal ");
  810.             st = ftos(Goal.goal_no);
  811.             bprint(st);
  812.             bprint(" has goal_group bit ");
  813.             st = ftos(TFGG_ACTIVATE_ALL);
  814.             bprint(st);
  815.             bprint(" set, but no .dmg specified.\n");
  816.         }
  817.         else
  818.         {
  819.             // Find all goals
  820.             tg = find (world, classname, "info_tfgoal");
  821.             while (tg)
  822.             {
  823.                 if (tg.group_no == Goal.dmg)
  824.                 {
  825.                     if (tg.goal_state == TFGS_ACTIVE)
  826.                     {
  827.                         tg.goal_state = TFGS_INACTIVE;
  828.                         tg.solid = SOLID_TRIGGER;
  829.                     }
  830.                 }
  831.         
  832.                 tg = find(tg, classname, "info_tfgoal");
  833.             }
  834.         }
  835.     }
  836.  
  837.     // Check Remove all in the group flag
  838.     if (Goal.goal_group & TFGG_REMOVE_ALL)
  839.     {
  840.         // Make sure a valid group no is specified
  841.         if (Goal.cnt == 0)
  842.         {
  843.             // No goal specified in .cnt. Print error.
  844.             bprint("Goal ");
  845.             st = ftos(Goal.goal_no);
  846.             bprint(st);
  847.             bprint(" has goal_group bit ");
  848.             st = ftos(TFGG_ACTIVATE_ALL);
  849.             bprint(st);
  850.             bprint(" set, but no .cnt specified.\n");
  851.         }
  852.         else
  853.         {
  854.             // Find all goals
  855.             tg = find (world, classname, "info_tfgoal");
  856.             while (tg)
  857.             {
  858.                 if (tg.group_no == Goal.cnt)
  859.                 {
  860.                     tg.goal_state = TFGS_REMOVED;
  861.                     tg.solid = SOLID_NOT;
  862.                 }
  863.         
  864.                 tg = find(tg, classname, "info_tfgoal");
  865.             }
  866.         }
  867.     }
  868.     
  869.     // Check Restore all in the group flag
  870.     if (Goal.goal_group & TFGG_RESTORE_ALL)
  871.     {
  872.         // Make sure a valid group no is specified
  873.         if (Goal.pausetime == 0)
  874.         {
  875.             // No goal specified in .pausetime. Print error.
  876.             bprint("Goal ");
  877.             st = ftos(Goal.goal_no);
  878.             bprint(st);
  879.             bprint(" has goal_group bit ");
  880.             st = ftos(TFGG_ACTIVATE_ALL);
  881.             bprint(st);
  882.             bprint(" set, but no .pausetime specified.\n");
  883.         }
  884.         else
  885.         {
  886.             // Find all goals
  887.             tg = find (world, classname, "info_tfgoal");
  888.             while (tg)
  889.             {
  890.                 if (tg.group_no == Goal.pausetime)
  891.                 {
  892.                     if (tg.goal_state == TFGS_REMOVED)
  893.                     {
  894.                         tg.goal_state = TFGS_INACTIVE;
  895.                         tg.solid = SOLID_TRIGGER;
  896.                     }
  897.                 }
  898.         
  899.                 tg = find(tg, classname, "info_tfgoal");
  900.             }
  901.         }
  902.     }
  903. };
  904.  
  905. //=========================================================================
  906. // Return the goal with a goal_no equal to gno
  907. entity(float gno) tfgoal_findgoal =
  908. {
  909.     local entity tg;
  910.     local string st;
  911.  
  912.     // Look for the goal
  913.     tg = find (world, classname, "info_tfgoal");
  914.     while (tg)
  915.     {
  916.         if (tg.goal_no == gno)
  917.         {
  918.             return tg;
  919.         }
  920.  
  921.         tg = find(tg, classname, "info_tfgoal");
  922.     }
  923.  
  924.     // Goal does not exist
  925.     bprint("Could not find a goal with a goal_no of ");
  926.     st = ftos(gno);
  927.     bprint(st);
  928.     bprint(".\n");
  929. };
  930.  
  931.  
  932.  
  933. //=========================================================================
  934. // GOALITEM FUNCTIONS
  935. //=========================================================================
  936. // Spawn the goalitem entity
  937. void() item_tfgoal =
  938. {
  939.     // Graphic
  940.     if (self.mdl)
  941.     {
  942.         precache_model2(self.mdl);
  943.         setmodel(self, self.mdl);
  944.     }
  945.     else
  946.     {
  947.         // Default mdl for a GoalItem that shouldn't be seen
  948.         self.mdl = "progs/w_s_key.mdl";
  949.         precache_model("progs/w_s_key.mdl");
  950.         setmodel(self, "progs/w_s_key.mdl");
  951.     }
  952.  
  953.     // Respawn sound
  954.     precache_sound2("items/itembk2.wav");
  955.  
  956.     // Collection sound
  957.     if (self.noise)
  958.     {
  959.         precache_sound2(self.noise);
  960.     }
  961.     else
  962.     {
  963.         // Default wav sound for a GoalItem collection
  964.         self.noise = "misc/basekey.wav";
  965.         precache_sound2("misc/basekey.wav");
  966.     }
  967.  
  968.     self.touch = item_tfgoal_touch;
  969.     self.goal_state = TFGS_INACTIVE;
  970.  
  971.     // Should this be placed on the map?
  972.     if (self.goal_activation & TFGI_NOEXIST)
  973.     {
  974.         self.solid = SOLID_NOT;
  975.     }
  976.     else
  977.     {
  978.         self.solid = SOLID_TRIGGER;
  979.         setmodel(self, self.mdl);
  980.         setorigin(self, self.origin);
  981.     }
  982.  
  983.     if (!(self.netname))
  984.         self.netname = "goalitem";
  985.  
  986.     if (self.delay <= 0)
  987.         self.delay = 120;
  988.     setsize (self, '-16 -16 -24', '16 16 32');
  989.     TF_StartItem ();
  990. };
  991.  
  992. //=========================================================================
  993. // Touch function for the goalitem entity
  994. void() item_tfgoal_touch =
  995. {
  996.     local string st;
  997.     local entity te;
  998.  
  999.     if (other.classname != "player")
  1000.         return;
  1001.  
  1002.     // Fortressmap is off?
  1003.     if (!(toggleflags & TFLAG_FORTRESSMAP))
  1004.         return;
  1005.  
  1006.     // If a player of a specific team can get this one
  1007.     if (self.goal_activation & TFGI_TEAM)
  1008.     {
  1009.         if (self.team_no != other.team_no)
  1010.             return;
  1011.     }
  1012.  
  1013.     // If a player must be of a particular class to get this one
  1014.     if (self.goal_activation & TFGI_CLASS)
  1015.     {
  1016.         if (self.playerclass != other.playerclass)
  1017.             return;
  1018.     }
  1019.  
  1020.     // If a player needs a GoalItem to be able to get this one
  1021.     if (self.goal_activation & TFGI_ITEM)
  1022.     {
  1023.         te = tfgoal_finditem(self.items_allowed);
  1024.         if (te.owner != other)
  1025.             return;
  1026.     }
  1027.  
  1028.     // Give it to the player
  1029.     tfgoalitem_GiveToAP(self, other);
  1030. };
  1031.  
  1032. //=========================================================================
  1033. // Return the item with a goal_no equal to ino
  1034. entity(float ino) tfgoal_finditem =
  1035. {
  1036.     local entity tg;
  1037.     local string st;
  1038.  
  1039.     // Look for the goal
  1040.     tg = find (world, classname, "item_tfgoal");
  1041.     while (tg)
  1042.     {
  1043.         if (tg.goal_no == ino)
  1044.         {
  1045.             return tg;
  1046.         }
  1047.  
  1048.         tg = find(tg, classname, "item_tfgoal");
  1049.     }
  1050.  
  1051.     // Goal does not exist
  1052.     bprint("Could not find an item with a goal_no of ");
  1053.     st = ftos(ino);
  1054.     bprint(st);
  1055.     bprint(".\n");
  1056. };
  1057.  
  1058. //=========================================================================
  1059. // Give the GoalItem to a Player. 
  1060. void(entity Item, entity AP) tfgoalitem_GiveToAP =
  1061. {
  1062.     local string sp;
  1063.  
  1064.     // Display the message
  1065.     if (Item.message)
  1066.         bprint(Item.message);
  1067.     if (Item.deathtype)
  1068.         sprint(AP, Item.deathtype);
  1069.  
  1070.     // Make the sound
  1071.     sound (other, CHAN_ITEM, Item.noise, 1, ATTN_NORM);
  1072.  
  1073.     Item.owner = AP;
  1074.     // Remove it from the map
  1075.     Item.model = string_null;
  1076.     Item.solid = SOLID_NOT;
  1077.  
  1078.     // Don't let it return
  1079.     Item.goal_state = TFGS_INACTIVE;
  1080.  
  1081.     // Do the deeds on the player
  1082.     if (Item.goal_activation & TFGI_GLOW)
  1083.         AP.effects = AP.effects | EF_BRIGHTLIGHT;
  1084.     if (Item.goal_activation & TFGI_SLOW)
  1085.     {
  1086.          AP.maxfbspeed = (AP.maxfbspeed / 2);
  1087.         AP.maxstrafespeed = (AP.maxstrafespeed / 2);
  1088.         sp = ftos(AP.maxfbspeed);
  1089.         stuffcmd(AP,"cl_backspeed ");
  1090.         stuffcmd(AP,sp);
  1091.         stuffcmd(AP,"\n");
  1092.         stuffcmd(AP,"cl_forwardspeed ");
  1093.         stuffcmd(AP,sp);
  1094.         stuffcmd(AP,"\n");
  1095.         sp = ftos(AP.maxstrafespeed);
  1096.         stuffcmd(AP,"cl_sidespeed ");
  1097.         stuffcmd(AP,sp);
  1098.         stuffcmd(AP,"\n");
  1099.     }
  1100. };
  1101.  
  1102. //=========================================================================
  1103. // Remove the GoalItem from a Player. self = item, other = player
  1104. void(entity Item, entity AP, float method) tfgoalitem_RemoveFromAP =
  1105. {
  1106.     local entity oldself;
  1107.  
  1108.     // Remove the deeds from the player
  1109.     AP.effects = AP.effects - (AP.effects & EF_BRIGHTLIGHT);
  1110.     if (Item.goal_activation & TFGI_SLOW)
  1111.     {
  1112.         oldself = self;
  1113.         self = AP;
  1114.         TeamFortress_SetSpeed();
  1115.         self = oldself;
  1116.     }
  1117.  
  1118.     // Return it to the starting point if the flag is set
  1119.     if (method == 0)        // Dropped by a dying player
  1120.     {
  1121.         // Drop it if the flag is set
  1122.         if (Item.goal_activation & TFGI_DROP)
  1123.         {
  1124.             tfgoalitem_drop(Item);
  1125.         }
  1126.         else if (Item.goal_activation & TFGI_RETURN_DROP)
  1127.         {
  1128.             Item.solid = SOLID_TRIGGER;
  1129.             Item.touch = item_tfgoal_touch;
  1130.             Item.origin = Item.oldorigin;
  1131.             setmodel(Item, Item.mdl);
  1132.             setorigin(Item, Item.origin);
  1133.             sound (Item, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
  1134.  
  1135.             // Restore a goal if needed
  1136.             tfgoalitem_checkgoalreturn();
  1137.         }
  1138.         else
  1139.         {
  1140.             // Remove the Item
  1141.             remove(Item);
  1142.         }
  1143.         Item.owner = world;
  1144.         return;
  1145.     }
  1146.  
  1147.     // Return it to the starting point if the flag is set
  1148.     if (method == 1)        // Removed by a goal activation
  1149.     {
  1150.         if (Item.goal_activation & TFGI_RETURN_GOAL)
  1151.         {
  1152.             Item.solid = SOLID_TRIGGER;
  1153.             Item.touch = item_tfgoal_touch;
  1154.             Item.origin = Item.oldorigin;
  1155.             setmodel(Item, Item.mdl);
  1156.             setorigin(Item, Item.origin);
  1157.             sound (Item, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
  1158.  
  1159.             // Restore a goal if needed
  1160.             tfgoalitem_checkgoalreturn();
  1161.         }
  1162.  
  1163.         // Don't remove it anyway, since it may be given away again later
  1164.         self.solid = SOLID_NOT;
  1165.         Item.owner = world;
  1166.         return;
  1167.     }
  1168. };
  1169.  
  1170. //=========================================================================
  1171. // Drop the item just like a backpack
  1172. void(entity Item) tfgoalitem_drop =
  1173. {
  1174.     Item.origin = Item.owner.origin - '0 0 24';
  1175.     
  1176.     Item.velocity_z = 300;
  1177.     Item.velocity_x = -100 + (random() * 200);
  1178.     Item.velocity_y = -100 + (random() * 200);
  1179.     
  1180.     Item.movetype = MOVETYPE_TOSS;
  1181.     Item.solid = SOLID_TRIGGER;
  1182.     Item.touch = item_tfgoal_touch;
  1183.     setorigin(Item, Item.origin);
  1184.     setmodel(Item, Item.mdl);
  1185.  
  1186.     // If the flag is set, remove it after 2 minutes
  1187.     if (Item.goal_activation & TFGI_REMOVE)
  1188.     {
  1189.         Item.goal_state = TFGS_ACTIVE;
  1190.         Item.nextthink = time + Item.delay;    
  1191.         Item.think = tfgoalitem_remove;
  1192.     }
  1193. };
  1194.  
  1195. //=========================================================================
  1196. // Remove the item, or Return it if needed
  1197. void() tfgoalitem_remove =
  1198. {
  1199.     // Has someone picked it up?
  1200.     if (self.goal_state != TFGS_ACTIVE)
  1201.         return;
  1202.  
  1203.     // Should it be returned?
  1204.     if (self.goal_activation & TFGI_RETURN_REMOVE)
  1205.     {
  1206.         self.solid = SOLID_TRIGGER;
  1207.         self.touch = item_tfgoal_touch;
  1208.         self.origin = self.oldorigin;
  1209.         setmodel(self, self.mdl);
  1210.         setorigin (self, self.origin);
  1211.         sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);    
  1212.  
  1213.         // Restore a goal if needed
  1214.         tfgoalitem_checkgoalreturn();
  1215.  
  1216.         return;
  1217.     }
  1218.  
  1219.     remove(self);
  1220. };
  1221.  
  1222. //=========================================================================
  1223. // Restore a goal when this item is removed, if needed
  1224. void() tfgoalitem_checkgoalreturn =
  1225. {
  1226.     local string st;
  1227.     local entity te;
  1228.  
  1229.     // Do we need to restore a goal somewhere?
  1230.     if (self.goal_activation & TFGI_RESTORE_GOAL)
  1231.     {
  1232.         if (self.impulse != 0)
  1233.         {
  1234.             // Find the goal
  1235.             te = tfgoal_findgoal(self.impulse);
  1236.             if (te)
  1237.             {
  1238.                 // Restore it
  1239.                 te.solid = SOLID_TRIGGER;
  1240.                 if (te.goal_state == TFGS_REMOVED)
  1241.                     te.goal_state = TFGS_INACTIVE;
  1242.             }
  1243.         }
  1244.         else
  1245.         {
  1246.             // No goal specified in .impulse. Print error.
  1247.             bprint("GoalItem ");
  1248.             st = ftos(self.goal_no);
  1249.             bprint(st);
  1250.             bprint(" has goal_activation bit ");
  1251.             st = ftos(TFGI_RESTORE_GOAL);
  1252.             bprint(st);
  1253.             bprint(" set, but no .impulse specified.\n");
  1254.         }
  1255.     }
  1256. };